#pragma once

#include "log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
//#include "thread_pool.hpp"
//#include <sys/wait.h>
#include <pthread.h>

using namespace LogModule;

//typedef std::function<void(void)> task_t;

typedef std::function<std::string(const std::string&)> func_t;

class TcpServer : Nocopy
{
public:
    TcpServer(uint16_t port, func_t func)
        :_port(port)
        , _func(func)
    {}

    void Init()
    {
        //创建套接字
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listensockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket error";
            exit((int)exit_code::SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success: " << _listensockfd;

        //绑定套接字
        InetAddr local(_port);
        int n = bind(_listensockfd, local.NetAddrPtr(), local.AddrLen());
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            exit((int)exit_code::BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success: " << _listensockfd;

        //启动监听
        n = listen(_listensockfd, 8);
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            exit((int)(exit_code::LISTEN_ERR));
        }
        LOG(LogLevel::INFO) << "listen success: " << _listensockfd;
    }

    void Service(int sockfd, InetAddr& peer)
    {
        char buffer[1024];
        while(true)
        {
            //读取消息
            int n = read(sockfd, buffer, sizeof(buffer) - 1);
            if(n > 0)
            {
                buffer[n] = '\0';
                LOG(LogLevel::INFO) << peer.StringAddr() << " say: " << buffer;

                //业务处理
                std::string echo_string = _func(buffer);

                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if(n == 0)
            {
                LOG(LogLevel::DEBUG) << peer.StringAddr() << "退出了";
                break;
            }
            else if(n < 0)
            {
                LOG(LogLevel::DEBUG) << peer.StringAddr() << "读取异常";
                break;
            }
        }
    }

    class ThreadData
    {  
    public:
        ThreadData(int sockfd, const InetAddr& addr, TcpServer* s)
            :_sockfd(sockfd)
            , _addr(addr)
            , tsvr(s)
        {}
        InetAddr _addr;
        int _sockfd;
        TcpServer* tsvr;
    };

    static void* Routine(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* p = (ThreadData*)args;
        p->tsvr->Service(p->_sockfd, p->_addr);
        delete p;
        return nullptr;
    }

    void Run()
    {
        _isrunning = true;
        
        while(_isrunning)
        {
            //获取连接
            struct sockaddr_in peer;
            socklen_t len = sizeof peer;
            int sockfd = accept(_listensockfd, (struct sockaddr*)&peer, &len);
            if(sockfd < 0)
            {
                LOG(LogLevel::WARING) << "accept error";
                continue;
            }

            InetAddr addr(peer);
            LOG(LogLevel::INFO) << "accept success: " << addr.StringAddr();

            // //单进程版
            // Service(sockfd, addr);


            // //多进程版
            // pid_t id = fork();
            // if(id < 0)
            // {
            //     LOG(LogLevel::FATAL) << "fork error";
            //     exit((int)exit_code::FORK_ERR);
            // }
            // if(id == 0)//子进程，完成与客户端的交互
            // {
            //     //子进程不需要再管连接用户的事
            //     close(_listensockfd);

            //     //让孙子进程完成，子进程退出，这样就不会让父进程阻塞住，就可以去处理其他用户连接
            //     if(fork() > 0) exit((int)exit_code::OK);

            //     //孙子进程完成与客户端交互，退出时让1号进程回收
            //     Service(sockfd, addr);
            //     exit((int)exit_code::OK);
            // }
            // else // 父进程 -- 等待子进程
            // {
            //     close(sockfd); // 父进程不再需要管与用户交互的事
            //     waitpid(id, nullptr, 0);
            // }


            //多线程版
            ThreadData* p = new ThreadData(sockfd, addr, this);
            pthread_t tid = 0;
            pthread_create(&tid, nullptr, Routine, p);


            // //线程池版
            // ThreadPool<task_t>::getInstance()->Push([this, &sockfd, &addr](){
            //     this->Service(sockfd, addr);
            // });
        }
        _isrunning = false;
    }
private:
    int _listensockfd = -1; // 监听socket
    uint16_t _port; // 端口号

    bool _isrunning = false; // 运行状态

    func_t _func; // 业务
};